﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using System.Drawing;
using LED_Editor.ControllerProgramming;
using LED_Editor.Model;

namespace LED_UnitTest
{
    [TestFixture]
    public class TestFramesConverter
    {
        [SetUp]
        public void  Setup()
        {
            FramesConverter.AddEmptyFrameAtEnd = false;
            FramesConverter.MaxFrameDuration = 255;
        }

        static DateTime Empty = new DateTime(1, 1, 1, 0, 0, 0, 0);
        [Test]
        public void Test_ConvertZeroLengthFrame()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
            //frame1.End  = Empty.AddMinutes(0) ;
            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;
            Assert.AreEqual(0, frame1.FrameDuration );



            FrameStruct [] frames = FramesConverter.Instance.Convert(new[] { frame1 });

            Assert.AreEqual(0, frames.Length);
        }

        [Test]
        public void Test_Stokhastical()
        {
            int accumulatedDuration = 0;
            Random random = new Random();

            List<Frame> sourceFrames = new List<Frame>(); 
            for (int i = 0; i < 10; i++)
            {
                Frame frame1 = Frame.CreateInstance();
                frame1.StartMarker = accumulatedDuration;
                frame1.FrameDuration = random.Next(100, 10000);
                accumulatedDuration += frame1.FrameDuration;
                Assert.AreEqual(frame1.StartMarker + frame1.FrameDuration, frame1.EndMarker);

                frame1.StartColor = Color.FromArgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
                frame1.EndColor = Color.FromArgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));

                sourceFrames.Add(frame1);
            }



            FrameStruct[] frames = FramesConverter.Instance.Convert(sourceFrames);

            for (int i = 0; i < frames.Length - 1; i++)
            {
                FrameStruct current = frames[i];
                FrameStruct next = frames[i + 1];

                AssertAreColorsEquals(current.EndColor, next.StartColor,"at iteration "+i);
                Assert.AreEqual(current.EndMarker, next.StartMarker);
            }
        }

        [Test]
        public void Test_ConvertOneFrame()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
           // frame1.End = Empty.AddMinutes(1);
            frame1.StartMarker = 0;
            frame1.FrameDuration = 100;
            Assert.AreEqual(100, frame1.EndMarker);
            Assert.AreEqual(100, frame1.FrameDuration);


            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;



            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1 });
            Assert.AreEqual(1, frames.Length);
            Assert.AreEqual(100, frames[0].Duration );
            AssertAreColorsEquals(Color.Red, frames[0].StartColor);
            AssertAreColorsEquals(Color.Yellow, frames[0].EndColor);

        }

        [Test]
        public void Test_ConvertOneLongFrame()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
            //frame1.End = Empty.AddMinutes(1000);

            frame1.StartMarker = 0;
            frame1.FrameDuration = 1000;
            Assert.AreEqual(1000, frame1.EndMarker);
            Assert.AreEqual(1000, frame1.FrameDuration);


            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;
            Assert.AreEqual(1000, frame1.FrameDuration);



            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1 });
            Assert.AreEqual(4, frames.Length);

            Assert.AreEqual(255, frames[0].Duration);
            AssertAreColorsEquals(Color.Red, frames[0].StartColor);

            AssertAreColorsEquals(Color.Yellow, frames[3].EndColor);


        }

        [Test]
        public void Test_ConvertOneLongFrameFromBlackToWhite()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
            //frame1.End = Empty.AddMinutes(510);

            frame1.StartMarker = 0;
            frame1.FrameDuration = 510;
            Assert.AreEqual(510, frame1.EndMarker);
            Assert.AreEqual(510, frame1.FrameDuration);


            frame1.StartColor = Color.Black ;
            frame1.EndColor = Color.White ;
            //Assert.AreEqual(510, frame1.FrameDuration);

            Color gray = Color.FromArgb(127, 127, 127);


            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1 });
            Assert.AreEqual(2, frames.Length);

            Assert.AreEqual(255, frames[0].Duration);
            Assert.AreEqual(255, frames[1].Duration);

            AssertAreColorsEquals(Color.Black, frames[0].StartColor);
            AssertAreColorsEquals(gray, frames[0].EndColor);

            AssertAreColorsEquals(gray, frames[1].StartColor);
            AssertAreColorsEquals(Color.White, frames[1].EndColor);
        }


        [Test]
        public void Test_ConvertOneLongFrameFromBlackToWhite2()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
            //frame1.End = Empty.AddMinutes(1020);

            frame1.StartMarker = 0;
            frame1.FrameDuration = 1020;
            Assert.AreEqual(1020, frame1.EndMarker);
            Assert.AreEqual(1020, frame1.FrameDuration);

            frame1.StartColor = Color.Black;
            frame1.EndColor = Color.White;
            Assert.AreEqual(1020, frame1.FrameDuration);

            Color darkGray  = Color.FromArgb(63, 63, 63);
            Color gray      = Color.FromArgb(127, 127, 127);
            Color lightGray = Color.FromArgb(191, 191, 191);



            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1 });
            Assert.AreEqual(4, frames.Length);

            Assert.AreEqual(255, frames[0].Duration);
            Assert.AreEqual(255, frames[1].Duration);
            Assert.AreEqual(255, frames[2].Duration);
            Assert.AreEqual(255, frames[3].Duration);


            AssertAreColorsEquals(Color.Black, frames[0].StartColor);
            AssertAreColorsEquals(darkGray, frames[0].EndColor);

            AssertAreColorsEquals(darkGray, frames[1].StartColor);
            AssertAreColorsEquals(gray, frames[1].EndColor);

            AssertAreColorsEquals(gray, frames[2].StartColor);
            AssertAreColorsEquals(lightGray, frames[2].EndColor);

            AssertAreColorsEquals(lightGray, frames[3].StartColor);
            AssertAreColorsEquals(Color.White, frames[3].EndColor);
        }


        [Test]
        public void Test_ConvertDifferentFrames()
        {
            Frame frame1 = Frame.CreateInstance();
            frame1.StartMarker = 0;
            frame1.FrameDuration = 255;
            Assert.AreEqual(255, frame1.EndMarker);
            Assert.AreEqual(255, frame1.FrameDuration);
            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Red;

            Frame frame2 = Frame.CreateInstance();
            frame2.StartMarker = 255;
            frame2.FrameDuration = 510;
            Assert.AreEqual(765, frame2.EndMarker);
            Assert.AreEqual(510, frame2.FrameDuration);
            frame2.StartColor = Color.Orange;
            frame2.EndColor = Color.Orange;

            Frame frame3 = Frame.CreateInstance();
            frame3.StartMarker = 765;
            frame3.FrameDuration = 765;
            Assert.AreEqual(1530, frame3.EndMarker);
            Assert.AreEqual(765, frame3.FrameDuration);
            frame3.StartColor = Color.Yellow;
            frame3.EndColor = Color.Green ;

            Frame frame4 = Frame.CreateInstance();
            frame4.StartMarker = 1530;
            frame4.FrameDuration = 1020;
            Assert.AreEqual(2550, frame4.EndMarker);
            Assert.AreEqual(1020, frame4.FrameDuration);
            frame4.StartColor = Color.Green;
            frame4.EndColor = Color.Blue ;





            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1, frame2, frame3, frame4 });
            Assert.AreEqual(10, frames.Length);

            foreach (var item in frames)
            {
                  Assert.AreEqual(255, item.Duration);
            }


            AssertAreColorsEquals(Color.Red, frames[0].StartColor);
            AssertAreColorsEquals(Color.Red, frames[0].EndColor);

            AssertAreColorsEquals(Color.Orange, frames[1].StartColor);
            AssertAreColorsEquals(Color.Orange, frames[1].EndColor);

            AssertAreColorsEquals(Color.Orange, frames[2].StartColor);
            AssertAreColorsEquals(Color.Orange, frames[2].EndColor);

            AssertAreColorsEquals(Color.Yellow  , frames[3].StartColor);
            AssertAreColorsEquals(frames[3].EndColor, frames[4].StartColor);
            AssertAreColorsEquals(frames[4].EndColor, frames[5].StartColor);
            AssertAreColorsEquals(Color.Green, frames[5].EndColor);

            AssertAreColorsEquals(Color.Green, frames[6].StartColor);
            AssertAreColorsEquals(frames[6].EndColor, frames[7].StartColor);
            AssertAreColorsEquals(frames[7].EndColor, frames[8].StartColor);
            AssertAreColorsEquals(frames[8].EndColor, frames[9].StartColor);
            AssertAreColorsEquals(Color.Blue, frames[9].EndColor);





            //AssertAreColorsEquals(darkGray, frames[1].StartColor);
            //AssertAreColorsEquals(gray, frames[1].EndColor);

            //AssertAreColorsEquals(gray, frames[2].StartColor);
            //AssertAreColorsEquals(lightGray, frames[2].EndColor);

            //AssertAreColorsEquals(lightGray, frames[3].StartColor);
            //AssertAreColorsEquals(Color.White, frames[3].EndColor);
        }



        [Test]
        public void Test_ConvertTwoContinuousFrames()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
            //frame1.End = Empty.AddMinutes(1);

            frame1.StartMarker = 0;
            frame1.FrameDuration = 1;
            Assert.AreEqual(1, frame1.EndMarker);
            Assert.AreEqual(1, frame1.FrameDuration);


            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;
            Assert.AreEqual(1, frame1.FrameDuration);

            Frame frame2 = Frame.CreateInstance();
            //frame2.Start = Empty.AddMinutes(1);
            //frame2.End = Empty.AddMinutes(2);

            frame2.StartMarker = 1;
            frame2.FrameDuration = 1;
            Assert.AreEqual(2, frame2.EndMarker);
            Assert.AreEqual(1, frame2.FrameDuration);


            frame2.StartColor = Color.Green ;
            frame2.EndColor = Color.Blue;
            Assert.AreEqual(1, frame2.FrameDuration);



            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1, frame2 });
            Assert.AreEqual(2, frames.Length);
            AssertAreColorsEquals(Color.Red, frames[0].StartColor);
            AssertAreColorsEquals(Color.Yellow, frames[0].EndColor);

            AssertAreColorsEquals(Color.Green, frames[1].StartColor);
            AssertAreColorsEquals(Color.Blue, frames[1].EndColor);


        }

        [Test]
        public void Test_ConvertTwoLongContinuousFrames()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
           // frame1.End = Empty.AddMinutes(1000);

            frame1.StartMarker = 0;
            frame1.FrameDuration = 1000;
            Assert.AreEqual(1000, frame1.EndMarker);
            Assert.AreEqual(1000, frame1.FrameDuration);


            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;
            Assert.AreEqual(1000, frame1.FrameDuration);

            Frame frame2 = Frame.CreateInstance();
            //frame2.Start = Empty.AddMinutes(1000);
           // frame2.End = Empty.AddMinutes(2000);

            frame2.StartMarker = 1000;
            frame2.FrameDuration = 1000;
            Assert.AreEqual(2000, frame2.EndMarker);
            Assert.AreEqual(1000, frame2.FrameDuration);


            frame2.StartColor = Color.Green;
            frame2.EndColor = Color.Blue;
            Assert.AreEqual(1000, frame2.FrameDuration);



            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1, frame2 });
            Assert.AreEqual(8, frames.Length);


            Assert.AreEqual(255, frames[0].Duration);
            Assert.AreEqual(255, frames[1].Duration);
            Assert.AreEqual(255, frames[2].Duration);
            Assert.AreEqual(235, frames[3].Duration);


            AssertAreColorsEquals(Color.Red, frames[0].StartColor);
            AssertAreColorsEquals(Color.Yellow, frames[3].EndColor);


            Assert.AreEqual(255, frames[4].Duration);
            Assert.AreEqual(255, frames[5].Duration);
            Assert.AreEqual(255, frames[6].Duration);
            Assert.AreEqual(235, frames[7].Duration);

            AssertAreColorsEquals(Color.Green, frames[4].StartColor);
            AssertAreColorsEquals(Color.Blue, frames[7].EndColor);


        }


        [Test]
        public void Test_ConvertTwoFramesWithPause()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
            //frame1.End = Empty.AddMinutes(1);

            frame1.StartMarker = 0;
            frame1.FrameDuration = 1;
            Assert.AreEqual(1, frame1.EndMarker);
            Assert.AreEqual(1, frame1.FrameDuration);

            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;
            Assert.AreEqual(1, frame1.FrameDuration);

            Frame frame2 = Frame.CreateInstance();
            //frame2.Start = Empty.AddMinutes(2);
            //frame2.End = Empty.AddMinutes(3);

            frame2.StartMarker = 2;
            frame2.FrameDuration = 1;
            Assert.AreEqual(3, frame2.EndMarker);
            Assert.AreEqual(1, frame2.FrameDuration);


            frame2.StartColor = Color.Green;
            frame2.EndColor = Color.Blue;
            Assert.AreEqual(1, frame2.FrameDuration);



            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1, frame2 });
            Assert.AreEqual(3, frames.Length);
            AssertAreColorsEquals(Color.Red, frames[0].StartColor);
            AssertAreColorsEquals(Color.Yellow, frames[0].EndColor);

            AssertAreColorsEquals(Color.Black, frames[1].StartColor);
            AssertAreColorsEquals(Color.Black, frames[1].EndColor);

            AssertAreColorsEquals(Color.Green, frames[2].StartColor);
            AssertAreColorsEquals(Color.Blue, frames[2].EndColor);


        }

        [Test]
        public void Test_ConvertTwoLongFramesWithPause()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
           // frame1.End = Empty.AddMinutes(1000);
            frame1.StartMarker = 0;
            frame1.FrameDuration = 1000;
            Assert.AreEqual(1000, frame1.EndMarker);
            Assert.AreEqual(1000, frame1.FrameDuration);

            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;
            Assert.AreEqual(1000, frame1.FrameDuration);

            Frame frame2 = Frame.CreateInstance();
           // frame2.Start = Empty.AddMinutes(2000);
           // frame2.End = Empty.AddMinutes(3000);
            frame2.StartMarker = 2000;
            frame2.FrameDuration = 1000;
            Assert.AreEqual(3000, frame2.EndMarker);
            Assert.AreEqual(1000, frame2.FrameDuration);

            frame2.StartColor = Color.Green;
            frame2.EndColor = Color.Blue;
            Assert.AreEqual(1000, frame2.FrameDuration);



            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1, frame2 });
            Assert.AreEqual(12, frames.Length);

            Assert.AreEqual(255, frames[0].Duration);
            Assert.AreEqual(255, frames[1].Duration);
            Assert.AreEqual(255, frames[2].Duration);
            Assert.AreEqual(235, frames[3].Duration);


            AssertAreColorsEquals(Color.Red,    frames[0].StartColor);
            AssertAreColorsEquals(Color.Yellow, frames[3].EndColor);



            Assert.AreEqual(255, frames[4].Duration);
            Assert.AreEqual(255, frames[5].Duration);
            Assert.AreEqual(255, frames[6].Duration);
            Assert.AreEqual(235, frames[7].Duration);

            AssertAreColorsEquals(Color.Black, frames[4].StartColor);
            AssertAreColorsEquals(Color.Black, frames[7].EndColor);



            Assert.AreEqual(255, frames[8].Duration);
            Assert.AreEqual(255, frames[9].Duration);
            Assert.AreEqual(255, frames[10].Duration);
            Assert.AreEqual(235, frames[11].Duration);

            AssertAreColorsEquals(Color.Green, frames[8].StartColor);
            AssertAreColorsEquals(Color.Blue, frames[11].EndColor);

        }



        [Test]
        public void Test_ConvertOneLongFrame_Sync()
        {
            Frame frame1 = Frame.CreateInstance();
            //frame1.Start = Empty;
            //frame1.End = Empty.AddMinutes(1000);

            frame1.StartMarker = 0;
            frame1.FrameDuration = 1000;
            Assert.AreEqual(1000, frame1.EndMarker);
            Assert.AreEqual(1000, frame1.FrameDuration);


            frame1.StartColor = Color.Red;
            frame1.EndColor = Color.Yellow;
            Assert.AreEqual(1000, frame1.FrameDuration);

            Frame sync = Frame.GetSyncronizationFrame(1000,2000);


            FramesConverter.AddEmptyFrameAtEnd = true;
            FrameStruct[] frames = FramesConverter.Instance.Convert(new[] { frame1, sync });
            Assert.IsTrue(frames.Length>0);

            Assert.AreEqual(255, frames[0].Duration);
            AssertAreColorsEquals(Color.Red, frames[0].StartColor);

            AssertAreColorsEquals(Color.Yellow, frames[3].EndColor);

            int duration = FrameStruct.GetDuration(frames);

            Assert.AreEqual(2000, duration);

            FrameStruct   last = frames[frames.Length - 1];
            Assert.AreEqual(0, last.Duration);
            Assert.IsTrue  (last.ColorsAreEqual );
            Assert.IsTrue(last.ColorsAreEmpty);


        }






        public static void AssertAreColorsEquals(Color expected, Color actual)
        {
            AssertAreColorsEquals(expected, actual, "-");
        }

        public static void AssertAreColorsEquals(Color expected, Color actual,string info)
        {
            if (expected.ToArgb() != actual.ToArgb())
            {
                Assert.Fail("Expected {0}, but actually was {1}. More: {2}", expected, actual, info);
            }
        }


    }
}
